package edu.kufpg.armatus.util;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.NavigableSet;
import java.util.Set;
import java.util.SortedSet;
import android.annotation.SuppressLint;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcelable;
import android.util.Log;
import android.util.SparseArray;
import com.google.common.base.Optional;
import com.google.common.collect.BoundType;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableRangeMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Range;
import com.google.common.collect.RangeMap;
import com.google.common.collect.SetMultimap;
public class BundleUtils {
private static final String TAG = BundleUtils.class.getSimpleName();
private static final String SIZE = "Size", KEY = "Key", VALUE = "Value", NULL = "Null", PRESENT_OR_NULL = "PresentOrNull";
private static final String NAME = "Name", NO_NAME = "!@#$%^&*()";
private static final String TYPE = "Type";
private static final String IS_LOWER_BOUNDED = "IsLowerBounded", IS_UPPER_BOUNDED = "IsUpperBounded";
private static final String LOWER_TYPE = "LowerType", LOWER_VALUE = "LowerValue", UPPER_TYPE = "UpperType", UPPER_VALUE = "UpperValue";
private static final String CREATE = "create";
private static final int VAL_NULL = -1;
private static final int VAL_STRING = 0;
private static final int VAL_INTEGER = 1;
private static final int VAL_MAP = 2;
private static final int VAL_BUNDLE = 3;
private static final int VAL_PARCELABLE = 4;
private static final int VAL_SHORT = 5;
private static final int VAL_LONG = 6;
private static final int VAL_FLOAT = 7;
private static final int VAL_DOUBLE = 8;
private static final int VAL_BOOLEAN = 9;
private static final int VAL_CHARSEQUENCE = 10;
private static final int VAL_LIST = 11;
private static final int VAL_SPARSEPARCELABLEARRAY = 12;
private static final int VAL_BYTEARRAY = 13;
private static final int VAL_STRINGARRAY = 14;
private static final int VAL_IBINDER = 15;
private static final int VAL_PARCELABLEARRAY = 16;
private static final int VAL_OBJECTARRAY = 17;
private static final int VAL_INTARRAY = 18;
private static final int VAL_LONGARRAY = 19;
private static final int VAL_BYTE = 20;
private static final int VAL_SERIALIZABLE = 21;
private static final int VAL_BOOLEANARRAY = 22;
private static final int VAL_CHARSEQUENCEARRAY = 23;
private static final int VAL_CHARARRAY = 24;
private static final int VAL_DOUBLEARRAY = 25;
private static final int VAL_FLOATARRAY = 26;
private static final int VAL_SHORTARRAY = 27;
private static final int VAL_MULTIMAP = 28;
private static final int VAL_OPTIONAL = 29;
private static final int VAL_RANGE = 30;
private static final int VAL_RANGEMAP = 31;
private static final int VAL_SET = 32;
//private static final int VAL_COLLECTION = 32;
private static final int VAL_ENUM = 33;
private BundleUtils() {}
private static Class<?> forName(String className) throws IllegalArgumentException {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
Log.e(TAG, "Illegal access when unmarshalling: "
+ className, e);
throw new IllegalArgumentException("ClassNotFoundException when unmarshalling: "
+ className);
}
}
private static boolean isAssignableFrom(Class<?> cls, String asgnName) throws IllegalArgumentException {
try {
return cls.isAssignableFrom(Class.forName(asgnName));
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException();
}
}
private static Object newInstance(String name) throws IllegalArgumentException {
try {
Class<?> c = Class.forName(name);
return c.newInstance();
} catch (ClassNotFoundException e) {
Log.e(TAG, "Illegal access when unmarshalling: "
+ name, e);
throw new IllegalArgumentException("ClassNotFoundException when unmarshalling: "
+ name);
} catch (InstantiationException e) {
Log.e(TAG, "Class not found when unmarshalling: "
+ name, e);
throw new IllegalArgumentException("InstantiationException when unmarshalling: "
+ name);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("IllegalAccessException when unmarshalling: "
+ name);
}
}
private static Object singletonInstance(String className, String singletonMethodName) throws IllegalArgumentException {
try {
Class<?> c = Class.forName(className);
Method m = c.getMethod(singletonMethodName);
return m.invoke(null);
} catch (ClassNotFoundException e) {
Log.e(TAG, "Illegal access when unmarshalling: "
+ className + " with method " + singletonMethodName, e);
throw new IllegalArgumentException("ClassNotFoundException when unmarshalling: "
+ className + " with method " + singletonMethodName);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("IllegalAccessException when unmarshalling: "
+ className + " with method " + singletonMethodName);
} catch (NoSuchMethodException e) {
Log.e(TAG, "Method not found when unmarshalling: "
+ className + " with method " + singletonMethodName, e);
throw new IllegalArgumentException("NoSuchMethodException when unmarshalling: "
+ className + " with method " + singletonMethodName);
} catch (InvocationTargetException e) {
throw new IllegalArgumentException("InvocationTargetException when unmarshalling: "
+ className + " with method " + singletonMethodName);
}
}
private static <E, C extends Collection<E>> C addToCollection(Bundle b, String key, C outVal, int size) {
for (int i = 0; i < size; i++) {
@SuppressWarnings("unchecked")
E elem = (E) getValue(b, key + i);
outVal.add(elem);
}
return outVal;
}
private static <E, ICB extends ImmutableCollection.Builder<E>> void addToImmutableCollectionBuilder(Bundle b, String key, ICB builder, int size) {
for (int i = 0; i < size; i++) {
@SuppressWarnings("unchecked")
E elem = (E) getValue(b, key + i);
builder.add(elem);
}
}
public static <T> T[] getArray(Bundle b, String key) {
int n = b.getInt(key + SIZE);
if (n < 0) {
return null;
} else {
Object[] outVal = new Object[n];
for (int i = 0; i < n; i++) {
@SuppressWarnings("unchecked")
T t = (T) getValue(b, key + i);
outVal[i] = t;
}
@SuppressWarnings("unchecked")
T[] ts = (T[]) outVal;
return ts;
}
}
public static <E extends Enum<E>> E getEnum(Bundle b, String key) {
String className = b.getString(key + NAME);
if (className.equals(NO_NAME)) {
return null;
} else {
@SuppressWarnings("unchecked")
Class<E> cls = (Class<E>) forName(className);
String valueName = b.getString(key);
return Enum.valueOf(cls, valueName);
}
}
public static <E> List<E> getList(Bundle b, String key) {
String name = b.getString(key + NAME);
if (isAssignableFrom(ImmutableList.class, name)) {
return getImmutableList(b, key);
} else if (name.equals(NO_NAME)) {
return null;
} else {
return getListInternal(b, key);
}
}
private static <E> List<E> getListInternal(Bundle b, String key) {
int n = b.getInt(key + SIZE);
String name = b.getString(key + NAME);
@SuppressWarnings("unchecked")
List<E> outVal = (List<E>) newInstance(name);
return addToCollection(b, key, outVal, n);
}
public static <E> ImmutableList<E> getImmutableList(Bundle b, String key) {
int n = b.getInt(key + SIZE);
ImmutableList.Builder<E> builder = ImmutableList.builder();
addToImmutableCollectionBuilder(b, key, builder, n);
return builder.build();
}
public static <K, V> Map<K, V> getMap(Bundle b, String key) {
String name = b.getString(key + NAME);
if (isAssignableFrom(ImmutableMap.class, name)) {
return getImmutableMap(b, key);
} else if (name.equals(NO_NAME)) {
return null;
} else {
return getMapInternal(b, key);
}
}
private static <K, V> Map<K, V> getMapInternal(Bundle b, String key) {
int n = b.getInt(key + SIZE);
String name = b.getString(key + NAME);
@SuppressWarnings("unchecked")
Map<K, V> outVal = (Map<K, V>) newInstance(name);
for (int i = 0; i < n; i++) {
@SuppressWarnings("unchecked")
K k = (K) getValue(b, key + KEY + i);
@SuppressWarnings("unchecked")
V v = (V) getValue(b, key + VALUE + i);
outVal.put(k, v);
}
return outVal;
}
public static <K, V> ImmutableMap<K, V> getImmutableMap(Bundle b, String key) {
int n = b.getInt(key + SIZE);
ImmutableMap.Builder<K, V> builder = ImmutableMap.builder();
for (int i = 0; i < n; i++) {
@SuppressWarnings("unchecked")
K k = (K) getValue(b, key + KEY + i);
@SuppressWarnings("unchecked")
V v = (V) getValue(b, key + VALUE + i);
builder.put(k, v);
}
return builder.build();
}
public static <K, V> Multimap<K, V> getMultimap(Bundle b, String key) {
String name = b.getString(key + NAME);
if (isAssignableFrom(ImmutableListMultimap.class, name)) {
return getImmutableListMultimap(b, key);
} else if (isAssignableFrom(ImmutableSetMultimap.class, name)) {
return getImmutableSetMultimap(b, key);
} else if (name.equals(NO_NAME)) {
return null;
} else {
return getMultimapInternal(b, key);
}
}
public static <K, V> ListMultimap<K, V> getListMultimap(Bundle b, String key) {
String name = b.getString(key + NAME);
if (isAssignableFrom(ImmutableListMultimap.class, name)) {
return getImmutableListMultimap(b, key);
} else if (name.equals(NO_NAME)) {
return null;
} else {
return getListMultimapInternal(b, key);
}
}
public static <K, V> SetMultimap<K, V> getSetMultimap(Bundle b, String key) {
String name = b.getString(key + NAME);
if (isAssignableFrom(ImmutableSetMultimap.class, name)) {
return getImmutableSetMultimap(b, key);
} else if (name.equals(NO_NAME)) {
return null;
} else {
return getSetMultimapInternal(b, key);
}
}
public static <K, V> ImmutableListMultimap<K, V> getImmutableListMultimap(Bundle b, String key) {
int n = b.getInt(key + SIZE);
ImmutableListMultimap.Builder<K, V> builder = ImmutableListMultimap.builder();
for (int i = 0; i < n; i++) {
@SuppressWarnings("unchecked")
K k = (K) getValue(b, key + KEY + i);
int q = b.getInt(key + KEY + SIZE + i);
for (int j = 0; j < q; j++) {
@SuppressWarnings("unchecked")
V v = (V) getValue(b, key + VALUE + i + j);
builder.put(k, v);
}
}
return builder.build();
}
public static <K, V> ImmutableSetMultimap<K, V> getImmutableSetMultimap(Bundle b, String key) {
int n = b.getInt(key + SIZE);
ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder();
for (int i = 0; i < n; i++) {
@SuppressWarnings("unchecked")
K k = (K) getValue(b, key + KEY + i);
int q = b.getInt(key + KEY + SIZE + i);
for (int j = 0; j < q; j++) {
@SuppressWarnings("unchecked")
V v = (V) getValue(b, key + VALUE + i + j);
builder.put(k, v);
}
}
return builder.build();
}
private static <K, V> Multimap<K, V> getMultimapInternal(Bundle b, String key) {
int n = b.getInt(key + SIZE);
String name = b.getString(key + NAME);
@SuppressWarnings("unchecked")
Multimap<K, V> outVal = (Multimap<K, V>) singletonInstance(name, CREATE);
for (int i = 0; i < n; i++) {
@SuppressWarnings("unchecked")
K k = (K) getValue(b, key + KEY + i);
int q = b.getInt(key + KEY + SIZE + i);
for (int j = 0; j < q; j++) {
@SuppressWarnings("unchecked")
V v = (V) getValue(b, key + VALUE + i + j);
outVal.put(k, v);
}
}
return outVal;
}
private static <K, V> ListMultimap<K, V> getListMultimapInternal(Bundle b, String key) {
int n = b.getInt(key + SIZE);
String name = b.getString(key + NAME);
@SuppressWarnings("unchecked")
ListMultimap<K, V> outVal = (ListMultimap<K, V>) singletonInstance(name, CREATE);
for (int i = 0; i < n; i++) {
@SuppressWarnings("unchecked")
K k = (K) getValue(b, key + KEY + i);
int q = b.getInt(key + KEY + SIZE + i);
for (int j = 0; j < q; j++) {
@SuppressWarnings("unchecked")
V v = (V) getValue(b, key + VALUE + i + j);
outVal.put(k, v);
}
}
return outVal;
}
private static <K, V> SetMultimap<K, V> getSetMultimapInternal(Bundle b, String key) {
int n = b.getInt(key + SIZE);
String name = b.getString(key + NAME);
@SuppressWarnings("unchecked")
SetMultimap<K, V> outVal = (SetMultimap<K, V>) singletonInstance(name, CREATE);
for (int i = 0; i < n; i++) {
@SuppressWarnings("unchecked")
K k = (K) getValue(b, key + KEY + i);
int q = b.getInt(key + KEY + SIZE + i);
for (int j = 0; j < q; j++) {
@SuppressWarnings("unchecked")
V v = (V) getValue(b, key + VALUE + i + j);
outVal.put(k, v);
}
}
return outVal;
}
public static <T> Optional<T> getOptional(Bundle b, String key) {
int s = b.getInt(key + PRESENT_OR_NULL);
if (s == -1) {
return null;
} else if (s == 0) {
return Optional.absent();
} else {
@SuppressWarnings("unchecked")
T thing = (T) getValue(b, key);
return Optional.of(thing);
}
}
public static <C extends Comparable<? super C>> Range<C> getRange(Bundle b, String key) {
if (b.getBoolean(key + NULL)) {
return null;
} else {
boolean isLowerBounded = b.getBoolean(key + IS_LOWER_BOUNDED);
boolean isUpperBounded = b.getBoolean(key + IS_UPPER_BOUNDED);
if (isLowerBounded && isUpperBounded) {
BoundType lowerType = getEnum(b, key + LOWER_TYPE);
@SuppressWarnings("unchecked")
C lowerVal = (C) getValue(b, key + LOWER_VALUE);
BoundType upperType = getEnum(b, key + UPPER_TYPE);
@SuppressWarnings("unchecked")
C upperVal = (C) getValue(b, key + UPPER_VALUE);
return Range.range(lowerVal, lowerType, upperVal, upperType);
} else if (isLowerBounded) {
BoundType lowerType = BoundType.values()[b.getInt(key + LOWER_TYPE)];
@SuppressWarnings("unchecked")
C lowerVal = (C) getValue(b, key + LOWER_VALUE);
return Range.downTo(lowerVal, lowerType);
} else if (isUpperBounded) {
BoundType upperType = BoundType.values()[b.getInt(key + UPPER_TYPE)];
@SuppressWarnings("unchecked")
C upperVal = (C) getValue(b, key + UPPER_VALUE);
return Range.upTo(upperVal, upperType);
} else {
return Range.all();
}
}
}
public static <K extends Comparable<? super K>, V> RangeMap<K, V> getRangeMap(Bundle b, String key) {
String name = b.getString(key + NAME);
if (isAssignableFrom(ImmutableRangeMap.class, name)) {
return getImmutableRangeMap(b, key);
} else if (name.equals(NO_NAME)) {
return null;
} else {
return getRangeMapInternal(b, key);
}
}
public static <K extends Comparable<? super K>, V> ImmutableRangeMap<K, V> getImmutableRangeMap(Bundle b, String key) {
int n = b.getInt(key + SIZE);
ImmutableRangeMap.Builder<K, V> builder = ImmutableRangeMap.builder();
for (int i = 0; i < n; i++) {
Range<K> range = getRange(b, key + KEY + i);
@SuppressWarnings("unchecked")
V value = (V) getValue(b, key + VALUE + i);
builder.put(range, value);
}
return builder.build();
}
private static <K extends Comparable<? super K>, V> RangeMap<K, V> getRangeMapInternal(Bundle b, String key) {
int n = b.getInt(key + SIZE);
String name = b.getString(key + NAME);
@SuppressWarnings("unchecked")
RangeMap<K, V> outVal = (RangeMap<K, V>) singletonInstance(name, CREATE);
for (int i = 0; i < n; i++) {
Range<K> range = getRange(b, key + KEY + i);
@SuppressWarnings("unchecked")
V value = (V) getValue(b, key + VALUE + i);
outVal.put(range, value);
}
return outVal;
}
public static <E> Set<E> getSet(Bundle b, String key) {
String name = b.getString(key + NAME);
if (isAssignableFrom(ImmutableSortedSet.class, name)) {
@SuppressWarnings("unchecked")
Set<E> set = (Set<E>) getImmutableSortedSet(b, key);
return set;
} else if (isAssignableFrom(ImmutableSet.class, name)) {
return getImmutableSet(b, key);
} else if (name.equals(NO_NAME)) {
return null;
} else {
return getSetInternal(b, key);
}
}
private static <E> Set<E> getSetInternal(Bundle b, String key) {
int n = b.getInt(key + SIZE);
String name = b.getString(key + NAME);
@SuppressWarnings("unchecked")
Set<E> outVal = (Set<E>) newInstance(name);
return addToCollection(b, key, outVal, n);
}
public static <E extends Comparable<? super E>> SortedSet<E> getSortedSet(Bundle b, String key) {
String name = b.getString(key + NAME);
if (isAssignableFrom(ImmutableSortedSet.class, name)) {
return getImmutableSortedSet(b, key);
} else if (name.equals(NO_NAME)) {
return null;
} else {
return getSortedSetInternal(b, key);
}
}
private static <E> SortedSet<E> getSortedSetInternal(Bundle b, String key) {
int n = b.getInt(key + SIZE);
String name = b.getString(key + NAME);
@SuppressWarnings("unchecked")
SortedSet<E> outVal = (SortedSet<E>) newInstance(name);
return addToCollection(b, key, outVal, n);
}
public static <E extends Comparable<? super E>> NavigableSet<E> getNavigableSet(Bundle b, String key) {
String name = b.getString(key + NAME);
if (isAssignableFrom(ImmutableSortedSet.class, name)) {
return getImmutableSortedSet(b, key);
} else if (name.equals(NO_NAME)) {
return null;
} else {
return getNavigableSetInternal(b, key);
}
}
private static <E> NavigableSet<E> getNavigableSetInternal(Bundle b, String key) {
int n = b.getInt(key + SIZE);
String name = b.getString(key + NAME);
@SuppressWarnings("unchecked")
NavigableSet<E> outVal = (NavigableSet<E>) newInstance(name);
return addToCollection(b, key, outVal, n);
}
public static <E> ImmutableSet<E> getImmutableSet(Bundle b, String key) {
if (b.getString(key + NAME).equals(NO_NAME)) {
return null;
} else {
int n = b.getInt(key + SIZE);
ImmutableSet.Builder<E> builder = ImmutableSet.builder();
addToImmutableCollectionBuilder(b, key, builder, n);
return builder.build();
}
}
public static <E extends Comparable<? super E>> ImmutableSortedSet<E> getImmutableSortedSet(Bundle b, String key) {
if (b.getString(key + NAME).equals(NO_NAME)) {
return null;
} else {
int n = b.getInt(key + SIZE);
ImmutableSortedSet.Builder<E> builder = ImmutableSortedSet.naturalOrder();
addToImmutableCollectionBuilder(b, key, builder, n);
return builder.build();
}
}
@SuppressLint("NewApi")
public static final Object getValue(Bundle b, String key) {
int type = b.getInt(key + TYPE);
switch (type) {
case VAL_NULL:
return null;
case VAL_ENUM:
return getEnum(b, key);
case VAL_OPTIONAL:
return getOptional(b, key);
case VAL_STRING:
return b.getString(key);
case VAL_INTEGER:
return b.getInt(key);
case VAL_MULTIMAP:
return getMultimap(b, key);
case VAL_RANGE:
return getRange(b, key);
case VAL_RANGEMAP:
return getRangeMap(b, key);
case VAL_MAP:
return getMap(b, key);
case VAL_PARCELABLE:
return b.getParcelable(key);
case VAL_SHORT:
return b.getShort(key);
case VAL_LONG:
return b.getLong(key);
case VAL_FLOAT:
return b.getFloat(key);
case VAL_DOUBLE:
return b.getDouble(key);
case VAL_BOOLEAN:
return b.getBoolean(key);
case VAL_CHARSEQUENCE:
return b.getCharSequence(key);
case VAL_LIST:
return getList(b, key);
case VAL_SET:
return getSet(b, key);
case VAL_BOOLEANARRAY:
return b.getBooleanArray(key);
case VAL_BYTEARRAY:
return b.getByteArray(key);
case VAL_STRINGARRAY:
return b.getStringArray(key);
case VAL_CHARSEQUENCEARRAY:
return b.getCharSequenceArray(key);
case VAL_CHARARRAY:
return b.getChar(key);
case VAL_DOUBLEARRAY:
return b.getDoubleArray(key);
case VAL_FLOATARRAY:
return b.getFloatArray(key);
case VAL_SHORTARRAY:
return b.getShortArray(key);
case VAL_IBINDER:
return b.getBinder(key);
case VAL_INTARRAY:
return b.getIntArray(key);
case VAL_LONGARRAY:
return b.getLongArray(key);
case VAL_OBJECTARRAY:
return getArray(b, key);
case VAL_BYTE:
return b.getByte(key);
case VAL_SERIALIZABLE:
return b.getSerializable(key);
case VAL_PARCELABLEARRAY:
return b.getParcelableArray(key);
case VAL_SPARSEPARCELABLEARRAY:
return b.getSparseParcelableArray(key);
case VAL_BUNDLE:
return b.getBundle(key); // loading will be deferred
default:
throw new RuntimeException(
"Parcel " + b + ": Unmarshalling unknown type code " + type);
}
}
public static <T> void putArray(Bundle b, String key, T[] value) {
if (value == null) {
b.putInt(key + SIZE, -1);
} else {
int n = value.length;
b.putInt(key + SIZE, n);
for (int i = 0; i < n; i++) {
putValue(b, key + i, value[i]);
}
}
}
public static <E extends Enum<?>> void putEnum(Bundle b, String key, E value) {
if (value == null) {
b.putString(key + NAME, NO_NAME);
} else {
b.putString(key + NAME, value.getDeclaringClass().getName());
b.putString(key, value.name());
}
}
public static <E> void putList(Bundle b, String key, List<E> value) {
if (value == null) {
b.putString(key + NAME, NO_NAME);
} else {
b.putString(key + NAME, value.getClass().getName());
int n = value.size();
b.putInt(key + SIZE, n);
for (int i = 0; i < n; i++) {
putValue(b, key + i, value.get(i));
}
}
}
public static <K, V> void putMap(Bundle b, String key, Map<K, V> value) {
if (value == null) {
b.putString(key + NAME, NO_NAME);
} else {
b.putString(key + NAME, value.getClass().getName());
int n = value.size();
b.putInt(key + SIZE, n);
int i = 0;
for (Map.Entry<K, V> entry : value.entrySet()) {
putValue(b, key + KEY + i, entry.getKey());
putValue(b, key + VALUE + i, entry.getValue());
i++;
}
}
}
public static <K, V> void putMultimap(Bundle b, String key, Multimap<K, V> value) {
if (value == null) {
b.putString(key + NAME, NO_NAME);
} else {
b.putString(key + NAME, value.getClass().getName());
int n = value.size();
b.putInt(key + SIZE, n);
int i = 0;
for (Map.Entry<K, Collection<V>> entry : value.asMap().entrySet()) {
putValue(b, key + KEY + i, entry.getKey());
int j = 0;
for (V v : entry.getValue()) {
putValue(b, key + VALUE + i + j, v);
j++;
}
b.putInt(key + KEY + SIZE + i, j);
i++;
}
}
}
public static <T> void putOptional(Bundle b, String key, Optional<T> value) {
if (value == null) {
b.putInt(key + PRESENT_OR_NULL, -1);
} else if (value.isPresent()) {
b.putInt(key + PRESENT_OR_NULL, 1);
putValue(b, key, value.get());
} else {
b.putInt(key + PRESENT_OR_NULL, 0);
}
}
public static <C extends Comparable<?>> void putRange(Bundle b, String key, Range<C> value) {
if (value == null) {
b.putBoolean(key + NULL, true);
} else {
b.putBoolean(key + NULL, false);
if (value.hasLowerBound()) {
b.putBoolean(key + IS_LOWER_BOUNDED, true);
putEnum(b, key + LOWER_TYPE, value.lowerBoundType());
putValue(b, key + LOWER_VALUE, value.lowerEndpoint());
} else {
b.putBoolean(key + IS_LOWER_BOUNDED, false);
}
if (value.hasUpperBound()) {
b.putBoolean(key + IS_UPPER_BOUNDED, true);
putEnum(b, key + UPPER_TYPE, value.upperBoundType());
putValue(b, key + UPPER_VALUE, value.upperEndpoint());
} else {
b.putBoolean(key + IS_UPPER_BOUNDED, false);
}
}
}
public static <K extends Comparable<?>, V> void putRangeMap(Bundle b, String key, RangeMap<K, V> value) {
if (value == null) {
b.putString(key + NAME, NO_NAME);
} else {
b.putString(key + NAME, value.getClass().getName());
int n = value.asMapOfRanges().size();
b.putInt(key + SIZE, n);
int i = 0;
for (Map.Entry<Range<K>, V> entry : value.asMapOfRanges().entrySet()) {
putRange(b, key + KEY + i, entry.getKey());
putValue(b, key + VALUE + i, entry.getValue());
i++;
}
}
}
public static <E> void putSet(Bundle b, String key, Set<E> value) {
if (value == null) {
b.putString(key + NAME, NO_NAME);
} else {
b.putString(key + NAME, value.getClass().getName());
int n = value.size();
b.putInt(key + SIZE, n);
int i = 0;
for (E elem : value) {
putValue(b, key + i, elem);
i++;
}
}
}
@SuppressLint("NewApi")
public static void putValue(Bundle b, String key, Object v) {
String keyType = key + TYPE;
if (v == null) {
b.putInt(keyType, VAL_NULL);
} else if (v.getClass().isEnum()) {
b.putInt(keyType, VAL_ENUM);
putEnum(b, key, (Enum<?>) v);
} else if (v instanceof Optional) {
b.putInt(keyType, VAL_OPTIONAL);
putOptional(b, key, (Optional<?>) v);
} else if (v instanceof String) {
b.putInt(keyType, VAL_STRING);
b.putString(key, (String) v);
} else if (v instanceof Integer) {
b.putInt(keyType, VAL_INTEGER);
b.putInt(key, (Integer) v);
} else if (v instanceof Multimap) {
b.putInt(keyType, VAL_MULTIMAP);
putMultimap(b, key, (Multimap<?,?>) v);
} else if (v instanceof Range) {
b.putInt(keyType, VAL_RANGE);
@SuppressWarnings("unchecked")
Range<? extends Comparable<?>> range = (Range<? extends Comparable<?>>) v;
putRange(b, key, range);
} else if (v instanceof RangeMap) {
b.putInt(keyType, VAL_RANGEMAP);
@SuppressWarnings("unchecked")
RangeMap<? extends Comparable<?>, ?> rangeMap = (RangeMap<? extends Comparable<?>, ?>) v;
putRangeMap(b, key, rangeMap);
} else if (v instanceof Map) {
b.putInt(keyType, VAL_MAP);
putMap(b, key, (Map<?,?>) v);
} else if (v instanceof Bundle) {
// Must be before Parcelable
b.putInt(keyType, VAL_BUNDLE);
b.putBundle(key, (Bundle) v);
} else if (v instanceof Parcelable) {
b.putInt(keyType, VAL_PARCELABLE);
b.putParcelable(key, (Parcelable) v);
} else if (v instanceof Short) {
b.putInt(keyType, VAL_SHORT);
b.putShort(key, (Short) v);
} else if (v instanceof Long) {
b.putInt(keyType, VAL_LONG);
b.putLong(key, (Long) v);
} else if (v instanceof Float) {
b.putInt(keyType, VAL_FLOAT);
b.putFloat(key, (Float) v);
} else if (v instanceof Double) {
b.putInt(keyType, VAL_DOUBLE);
b.putDouble(key, (Double) v);
} else if (v instanceof Boolean) {
b.putInt(keyType, VAL_BOOLEAN);
b.putBoolean(key, (Boolean) v);
} else if (v instanceof CharSequence) {
// Must be after String
b.putInt(keyType, VAL_CHARSEQUENCE);
b.putCharSequence(key, (CharSequence) v);
} else if (v instanceof List) {
b.putInt(keyType, VAL_LIST);
putList(b, key, (List<?>) v);
} else if (v instanceof Set) {
b.putInt(keyType, VAL_SET);
putSet(b, key, (Set<?>) v);
} else if (v instanceof SparseArray) {
b.putInt(keyType, VAL_SPARSEPARCELABLEARRAY);
@SuppressWarnings("unchecked")
SparseArray<? extends Parcelable> spa = (SparseArray<? extends Parcelable>) v;
b.putSparseParcelableArray(key, spa);
} else if (v instanceof boolean[]) {
b.putInt(keyType, VAL_BOOLEANARRAY);
b.putBooleanArray(key, (boolean[]) v);
} else if (v instanceof byte[]) {
b.putInt(keyType, VAL_BYTEARRAY);
b.putByteArray(key, (byte[]) v);
} else if (v instanceof String[]) {
b.putInt(keyType, VAL_STRINGARRAY);
b.putStringArray(key, (String[]) v);
} else if (v instanceof char[]) {
b.putInt(keyType, VAL_CHARARRAY);
b.putCharArray(key, (char[]) v);
} else if (v instanceof double[]) {
b.putInt(keyType, VAL_DOUBLEARRAY);
b.putDoubleArray(key, (double[]) v);
} else if (v instanceof float[]) {
b.putInt(keyType, VAL_FLOATARRAY);
b.putFloatArray(key, (float[]) v);
} else if (v instanceof short[]) {
b.putInt(keyType, VAL_SHORTARRAY);
b.putShortArray(key, (short[]) v);
} else if (v instanceof CharSequence[]) {
// Must be after String[] and before Object[]
b.putInt(keyType, VAL_CHARSEQUENCEARRAY);
b.putCharSequenceArray(key, (CharSequence[]) v);
} else if (v instanceof IBinder && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
b.putInt(keyType, VAL_IBINDER);
b.putBinder(key, (IBinder) v);
} else if (v instanceof Parcelable[]) {
b.putInt(keyType, VAL_PARCELABLEARRAY);
b.putParcelableArray(key, (Parcelable[]) v);
} else if (v instanceof int[]) {
b.putInt(keyType, VAL_INTARRAY);
b.putIntArray(key, (int[]) v);
} else if (v instanceof long[]) {
b.putInt(keyType, VAL_LONGARRAY);
b.putLongArray(key, (long[]) v);
} else if (v instanceof Object[]) {
b.putInt(keyType, VAL_OBJECTARRAY);
putArray(b, key, (Object[]) v);
} else if (v instanceof Byte) {
b.putInt(keyType, VAL_BYTE);
b.putByte(key, (Byte) v);
} else if (v instanceof Serializable) {
// Must be last
b.putInt(keyType, VAL_SERIALIZABLE);
b.putSerializable(key, (Serializable) v);
} else {
throw new RuntimeException("Parcel: unable to marshal value " + v);
}
}
}